package it.lorenz.server.fk.business;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import org.hibernate.Query;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component("baseDAO")
public class BaseDAO {

    @Autowired
    private SessionFactory sessionFactory;

    public void saveEntity(Object entity) {
        sessionFactory.getCurrentSession().save(entity);
    }

    public void saveEntities(List<Object> entities) {
        for (Object entity : entities) {
            sessionFactory.getCurrentSession().save(entity);
        }
    }

    public void updateEntity(Object entity) {
        sessionFactory.getCurrentSession().update(entity);
    }

    public void updateEntities(List<Object> entities) {
        for (Object entity : entities) {
            sessionFactory.getCurrentSession().update(entity);
        }
    }

    public void saveOrUpdateEntity(Object entity) {
        sessionFactory.getCurrentSession().saveOrUpdate(entity);
    }

    public void saveOrUpdateEntities(List<Object> entities) {
        for (Object entity : entities) {
            sessionFactory.getCurrentSession().saveOrUpdate(entity);
        }
    }

    @SuppressWarnings("unchecked")
    public <T> T getEntity(Class<? extends T> clazz, Serializable id) {
        return (T) sessionFactory.getCurrentSession().get(clazz, id);
    }

    @SuppressWarnings("unchecked")
    public <T> List<T> getEntities(Class<? extends T> clazz,
       List<Serializable> ids) {
        List<T> entities = new ArrayList<T>();
        for (Serializable id : ids) {
            entities.add((T) sessionFactory.getCurrentSession().get(clazz, id));
        }
        return entities;
    }

    public void deleteEntity(Object entity) {
        sessionFactory.getCurrentSession().delete(entity);
    }

    public void deleteEntities(List<Object> entities) {
        for (Object entity : entities) {
            sessionFactory.getCurrentSession().delete(entity);
        }
    }

    public <T> T selectQueryUniqueResult(Class<? extends T> clazz,
       String query, Object... params) {
        return executeQueryUniqueResult(clazz, sessionFactory
           .getCurrentSession().createQuery(query), params);
    }

    public <T> List<T> selectQueryMultipleResult(Class<? extends T> clazz,
       String query, Object... params) {
        return executeQueryMultipleResult(clazz, sessionFactory
           .getCurrentSession().createQuery(query), params);
    }

    public <T> T selectNamedQueryUniqueResult(Class<? extends T> clazz,
       String name, Object... params) {
        return executeQueryUniqueResult(clazz, sessionFactory
           .getCurrentSession().getNamedQuery(name), params);
    }

    public <T> List<T> selectNamedQueryMultipleResult(Class<? extends T> clazz,
       String name, Object... params) {
        return executeQueryMultipleResult(clazz, sessionFactory
           .getCurrentSession().getNamedQuery(name), params);
    }

    public int updateQuery(String query, Object... params) {
        return executeQueryUpdate(sessionFactory.getCurrentSession()
           .createQuery(query), params);
    }

    public int updateNamedQuery(String name, Object... params) {
        return executeQueryUpdate(sessionFactory.getCurrentSession()
           .getNamedQuery(name), params);
    }

    private void setQueryParameters(Query q, Object... params) {
        for (int i = 0; i < params.length; i++) {
            q.setParameter(String.valueOf(i + 1), params[i]);
        }
    }

    @SuppressWarnings("unchecked")
    private <T> T executeQueryUniqueResult(Class<? extends T> clazz, Query q,
       Object... params) {
        setQueryParameters(q, params);
        return (T) q.uniqueResult();
    }

    @SuppressWarnings("unchecked")
    private <T> List<T> executeQueryMultipleResult(Class<? extends T> clazz,
       Query q, Object... params) {
        setQueryParameters(q, params);
        return q.list();
    }

    private int executeQueryUpdate(Query q, Object... params) {
        setQueryParameters(q, params);
        return q.executeUpdate();
    }

    public SessionFactory getSessionFactory() {
        return sessionFactory;
    }

    public void setSessionFactory(SessionFactory sessionFactory) {
        this.sessionFactory = sessionFactory;
    }
}
